package com.admin.system.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.StrUtil;
import com.admin.model.base.PageResult;
import com.admin.model.dto.MenuDto;
import com.admin.model.pojo.Menu;
import com.admin.model.vo.MenuMetaVo;
import com.admin.model.vo.MenuTreeVo;
import com.admin.model.vo.MenuTreeVo2;
import com.admin.system.dao.CommonDao;
import com.admin.system.dao.MenuDao;
import com.admin.system.security.service.UserDetailsServiceImpl;
import com.admin.system.service.MenuService;
import com.admin.system.service.mapstruct.MenuMapper;
import com.baomidou.mybatisplus.core.toolkit.BeanUtils;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.yaml.snakeyaml.introspector.PropertyUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * (Menu)表服务实现类
 *
 * @author makejava
 * @since 2021-01-31 20:10:18
 */
@CacheConfig(cacheNames = "menu")
@Service("menuService")
public class MenuServiceImpl extends ServiceImpl<MenuDao, Menu> implements MenuService {
    @Resource
    private MenuDao menuDao;
    @Resource
    private CommonDao commonDao;
    @Resource
    private MenuMapper menuMapper;

    //@Cacheable(key = "'menus'+#pageSize", unless = "#pageNum>0")
    @Override
    public List<MenuDto> queryAll(MenuDto menuDto) {
        Menu menu = menuMapper.toEntity(menuDto);
        List<Menu> menus = menuDao.queryAll(menu);
        List<Menu> menuTree = menus.stream().filter(m -> m.getPid() == 0).map(m -> {
            m.setChildren(this.getChildren(m, menus));
            return m;
        }).collect(Collectors.toList());

        return menuMapper.toDto(menuTree);
    }

    private List<Menu> getChildren(Menu root, List<Menu> allListTree) {
        return allListTree.stream()
                .filter(treeEntity -> treeEntity.getPid().equals(root.getId()))
                .map(treeEntity -> {
                    treeEntity.setChildren(getChildren(treeEntity, allListTree));
                    return treeEntity;
                }).collect(Collectors.toList());
    }

    @Override
    public List<Tree<String>> buildTree() {
        List<Menu> list = new LambdaQueryChainWrapper<>(menuDao)
                .select(Menu::getId, Menu::getPid, Menu::getTitle, Menu::getType, Menu::getIcon)
                .list();
        //构建菜单树
        List<TreeNode<String>> treeNodes = list.stream().map(menu -> {
                    TreeNode<String> treeNode = new TreeNode<>(menu.getId().toString(), menu.getPid().toString(), menu.getTitle(), menu.getSort());
                    LinkedHashMap<String, Object> extraMap = new LinkedHashMap<>();
                    extraMap.put("type", menu.getType());
                    extraMap.put("icon", menu.getIcon());
                    extraMap.put("isDisabled", menu.getType() == 2);
                    treeNode.setExtra(extraMap);
                    return treeNode;
                }
        ).collect(Collectors.toList());
        return TreeUtil.build(treeNodes, "0");
    }


    @Override
    public MenuDto findById(Long id) {
        return menuMapper.toDto(menuDao.selectById(id));
    }

    //@CacheEvict(key = "'menus'", allEntries = true)
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void create(MenuDto menuDto) {
        Menu menu = menuMapper.toEntity(menuDto);
        if (menu.getPid() != 0 && menu.getPid() != null) {
            Menu parMenu = menuDao.selectById(menu.getPid());
            Assert.notNull(parMenu, "上级菜单不存在");
        }
        Optional<Menu> opt = new LambdaQueryChainWrapper<>(menuDao)
                .eq(Menu::getPid, menu.getPid())
                .eq(Menu::getType, menu.getType())
                .eq(Menu::getTitle, menu.getTitle())
                .last("limit 1")
                .oneOpt();
        Assert.isTrue(!opt.isPresent(), "菜单名称重复");
        if (menu.getType() == 2) menu.setIcon("function");
        int insert = menuDao.insert(menu);
        Assert.isTrue(insert > 0, "创建失败");
    }

    /*@Override
    public List<MenuTreeVo> buildTree(List<Menu> menus)  {
        List<MenuTreeVo> list = new LinkedList<>();
        menus.forEach(menu -> {
            if (!ObjectUtils.isEmpty(menu)) {
                MenuTreeVo treeVo = new MenuTreeVo();
                treeVo.setId(menu.getId());
                treeVo.setName(ObjectUtils.isEmpty(menu.getComponent()) ? menu.getTitle() : menu.getComponent());
                treeVo.setTitle(menu.getTitle());
                //顶层菜单加上"/"
                treeVo.setPath(menu.getPid() == 0 ? "/" + menu.getPath() : menu.getPath());
                treeVo.setHidden(menu.getHidden());
                if (!menu.getFrame()) {
                    //顶层菜单
                    if (menu.getPid() == 0) {
                        treeVo.setComponent(StringUtils.isEmpty(menu.getComponent()) ? "Layout" : menu.getComponent());
                    } else if (menu.getType() == 1) {
                        treeVo.setComponent(StringUtils.isEmpty(menu.getComponent()) ? "ParentView" : menu.getComponent());
                    } else if (!StringUtils.isEmpty(menu.getComponent())) {
                        treeVo.setComponent(menu.getComponent());
                    }
                }
                treeVo.setMeta(new MenuMetaVo(menu.getTitle(), menu.getIcon(), menu.getCache()));

                //添加子菜单
                if (CollectionUtil.isNotEmpty(menu.getChildren())) {
                    treeVo.setAlwaysShow(true);
                    treeVo.setRedirect("noredirect");
                    List<Menu> children = commonDao.findMenuByPId(menu.getId());
                    //List<Menu> children = menuDao.queryByPid(menu.getId());
                    if (CollectionUtil.isNotEmpty(children)) {
                        treeVo.setChildren(this.buildTree(children));
                    } else {
                        //无子菜单，且为顶层菜单
                        if (menu.getPid() == 0) {
                            MenuTreeVo menuTreeVo = new MenuTreeVo();
                            menuTreeVo.setMeta(treeVo.getMeta());
                            // 非外链
                            if (!menu.getFrame()) {
                                menuTreeVo.setPath("index");
                                menuTreeVo.setName(menu.getName());
                                menuTreeVo.setComponent(menu.getComponent());
                            } else {
                                menuTreeVo.setPath(menu.getPath());
                            }
                            treeVo.setName(null);
                            treeVo.setMeta(null);
                            treeVo.setComponent("Layout");
                            List<MenuTreeVo> list1 = new ArrayList<>();
                            list1.add(menuTreeVo);
                            treeVo.setChildren(list1);
                        }
                    }
                }
                list.add(treeVo);
            }
        });
        return list;
    }
*/
    @Override
    public List<MenuTreeVo> buildTree(List<Menu> menus) {

        //构建菜单树
        List<MenuTreeVo> menuTreeVos = menus.stream().map(menu -> {
            MenuTreeVo treeVo = new MenuTreeVo();
            treeVo.setId(menu.getId());
            treeVo.setPid(menu.getPid());
            //标题
            treeVo.setTitle(menu.getTitle());
            //隐藏
            treeVo.setHidden(menu.getHidden());
            treeVo.setMeta(new MenuMetaVo(menu.getTitle(), menu.getIcon(), menu.getCache()));


            //目录
            if (menu.getType() == 0) {
                //组件名称
                treeVo.setName(menu.getTitle());
                if (menu.getPid() == 0) {
                    treeVo.setAlwaysShow(true);
                    treeVo.setRedirect("noredirect");
                    //路径
                    treeVo.setPath("/" + menu.getPath());
                    //是否外链
                    if (!menu.getFrame()) {
                        treeVo.setComponent(StringUtils.isEmpty(menu.getComponent()) ? "Layout" : menu.getComponent());
                    }
                } else {
                    //路径
                    treeVo.setPath(menu.getPath());
                }

                //菜单
            } else if (menu.getType() == 1) {
                //路径
                treeVo.setPath(menu.getPath());
                if (!menu.getFrame()) {
                    treeVo.setComponent(StringUtils.isEmpty(menu.getComponent()) ? "ParentView" : menu.getComponent());
                }
            } else if (!StringUtils.isEmpty(menu.getComponent())) {
                //路径
                treeVo.setPath(menu.getPath());
                if (!menu.getFrame()) {
                    treeVo.setComponent(menu.getComponent());
                }
            }
            return treeVo;

        }).collect(Collectors.toList());
        return menuTreeVos.stream().filter(m -> m.getPid() == 0).map(m -> {
            m.setChildren(this.getChildren(m, menuTreeVos));
            return m;
        }).collect(Collectors.toList());
    }

    private List<MenuTreeVo> getChildren(MenuTreeVo root, List<MenuTreeVo> allListTree) {
        return allListTree.stream().filter((treeEntity) -> treeEntity.getPid().equals(root.getId())).map((treeEntity) -> {
            treeEntity.setChildren(this.getChildren(treeEntity, allListTree));
            return treeEntity;
        }).collect(Collectors.toList());
    }

    @Override
    public List<MenuDto> queryByPid(Long pid) {
        return menuMapper.toDto(menuDao.queryByPid(pid));
    }

    //@CacheEvict(key = "'menus'", allEntries = true)
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteByIds(Set<Long> ids) {
        ids.forEach(id -> {
            int delete = menuDao.deleteById(id);
            if (delete > 0) {
                // 查询出子菜单
                List<Menu> menus = menuDao.queryByPid(id);
                Set<Long> idList = menus.stream().map(Menu::getId).collect(Collectors.toSet());
                // 递归删除子菜单
                if (idList.size() > 0) {
                    menuDao.deleteBatchIds(idList);
                }
            }
        });
        //删除所有用户缓存
        UserDetailsServiceImpl.clearCachUserAll();
    }

    //@CacheEvict(key = "'menus'", allEntries = true)
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Menu updateById(MenuDto menuDto) {
        Menu menu = menuMapper.toEntity(menuDto);
        if (Objects.nonNull(menu.getPid()) && menu.getPid() != 0) {
            Optional.ofNullable(
                    menuDao.selectById(menu.getPid())
            ).orElseThrow(() -> new IllegalArgumentException("上级菜单不存在"));
        }

        int update = menuDao.updateById(menu);
        Assert.isTrue(update > 0, "更新失败");
        Optional<Menu> optional = new LambdaQueryChainWrapper<>(menuDao)
                .eq(Menu::getPid, menu.getPid())
                .eq(Menu::getType, menu.getType())
                .eq(Menu::getTitle, menu.getTitle())
                .last("limit 1")
                .oneOpt();
        Assert.isTrue(!optional.isPresent(), "菜单重复");
        //删除所有用户缓存
        UserDetailsServiceImpl.clearCachUserAll();
        return menuDao.selectById(menu.getId());
    }

    @Override
    public List<Menu> queryByUserId(Long userId) {
        return menuDao.queryByUserId(userId);
    }
}